import re

class RenrenUrlAssemblerBase:
    """ Assemble some interesting URL of Renren.
        Base class of RenRen Url Assembler.In this class, a legal renren url will be parsed and some necessary parameters will be extracted for further use.
        You may not want to instantiate this class directly, derive a subclass of it instead.
    """
        
    __id = ''
    " The key parameter of Renren URL."
    
    handler_list = list()
    " Handlers are callable objects receive ID as parameter and return something valuable."
        
    def parseid(self, u):
        """Mainly get the ID parameter from a URL.
        u is the URL I keep talking about, it should contain at least 'renren.com' which indicates its a link to our target.
        Conveniently, a string of 5~10 digitals is also acceptable which will be copied to __id attribute directly.
        """
        if re.match(r'^\s*\d{5,10}\s*$',u):
            self.__id= u.strip()
            return
        pattern = re.compile(r'^.*\.renren\.com.*[?&]id=(?P<id>\d+)') #Hey, replace the regex with a url parser
        result = pattern.match(u)
        if result:
            self.__id = result.group('id')
        else :
            raise ValueError(u + " is not a correct URL with required information.")

    def RegUrlhandler(self, handler):
        " Add a new handler to our handler list."
        self.handler_list.append(handler)

    def Assemble(self):
        """ Assemble all URLs by passing necessary parameters down to our handlers.
            A dictionary will be returned which contains handler-name-and-URL(s) pairs."""
        return dict([a(self.__id) for a in self.handler_list])

class UrlhandlerBase:
    """ A basic protocol of URL handler.
        All url handler should contain at least an identifiable class name and a handle method which recieves id as single parameter and generate a meaningful URL based on it.
    """
    name = 'Base'
    def handle(id_):
        " Recieve a id as parameter and return something you need."
        raise RuntimeWarning("Not implemented.")
    
class MobileAlbumhandler(UrlhandlerBase):
    """ A simple handler returns album URL of certain owner which towards the 3G version of Renren website.
        It's an important class because we can use the 3G version as an entry due to its lack of strong private protection policy, which allows us browse whosever albums, no matter it's your friend or not, even no matter the albums are shared with you or not.
        """
    name = 'MobileAlbum'
    def handle(id_):
        mobile_prefix = r'http://3g.renren.com/album/wmyalbum.do?id='
        if id_:
            return (MobileAlbumhandler.name,mobile_prefix + id_)
        else:
            raise SyntaxWarning("""Call URL assembling function prior to parsing id will get a general address.""" + mobile_prefix)

class NormalAlbumhandler(UrlhandlerBase):
    """ This class returns the album url towards normal www.renren.com.
        It's beneficial of at least two scenarios.
        Firstly, you want to browse someone's photos without leave any traces on its recent visitor list.
        Then, you've got some album links of 3G version, now you want their normal versions for clear vision.
    """
    name = 'NormalAlbum'
    def handle(id_):  
        url_fmt = r'http://photo.renren.com/photo/{}/album/relatives'
        if id_:
            return (NormalAlbumhandler.name,url_fmt.format(id_))
        else:
            raise SyntaxWarning("""Call URL assembling function prior to parsing id will get a general address.""" + url_fmt)

    def concrete(album_id_, own_id_):
        " Get the url of a certain album, indexed by its id and the id of its owner."
        url_fmt = r'http://photo.renren.com/photo/{}/album-{}'
        if album_id_ and own_id_:
            return url_fmt.format(own_id_,album_id_)
        else:
            raise SyntaxWarning("""Both own_id_ and album_id_ are required.""" )

class RenrenAlbumUrl(RenrenUrlAssemblerBase):
    __album_id = ''
    single_album_handler=None
    def __init__(self, IdUrl=None, s_handler=NormalAlbumhandler.concrete):
        if IdUrl:
            self.parseid(IdUrl)
        self.single_album_handler=s_handler
        self.RegUrlhandler(MobileAlbumhandler.handle)
        self.RegUrlhandler(NormalAlbumhandler.handle)

    def parseid(self, u):
        pattern = re.compile(r'^.*[?&]id=(?P<id>\d+).*[?&]owner=(?P<owner>\d+)')
        result = pattern.match(u)
        if result:
            self.__album_id = result.group('id')
            RenrenUrlAssemblerBase.parseid(self,result.group('owner'))
        else:
            RenrenUrlAssemblerBase.parseid(self,u)

    def album(self, u):
        self.__album_id =None
        self.parseid(u)
        if self.__album_id:
            return {'Album':self.single_album_handler(album_id_=self.__album_id,own_id_=self._RenrenUrlAssemblerBase__id)}
        else:
            return self.Assemble()

def main():
    from sys import stderr
    rau = RenrenAlbumUrl()
    u=''
    while True:
        try:
            u=input("Please input a URL: ")
            print()
            for k,v in rau.album(u).items():
                print("{}:\t{}".format(k,v))
            print()
        except ValueError as e:
            print(e,file=stderr)
        except KeyboardInterrupt:
            return

if __name__ == '__main__':
    main()
